package com.study.service.Impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.study.constant.CouponConstant;
import com.study.constant.OrderConstant;
import com.study.context.BaseContext;
import com.study.dto.*;
import com.study.entity.*;
import com.study.exception.OrderException;
import com.study.exception.UnauthorizedException;
import com.study.mapper.*;
import com.study.result.PageResult;
import com.study.service.OrderService;
import com.study.vo.OrderSubmitVO;
import com.study.vo.OrderVO;
import com.study.vo.OrdersDetailVO;
import com.study.vo.UserOrderDataVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Autowired
    Ordermapper orderMapper;
    @Autowired
    ActivityMapper activityMapper;
    @Autowired
    CouponMapper couponMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    OrderDetailMapper orderDetailMapper;
    @Autowired
    ImgResourceMapper imgResourceMapper;
    @Autowired
    CommentMapper commentMapper;

    /**
     * 获取用户我的页面订单数据
     *
     * @param userId
     * @return
     */
    @Override
    public UserOrderDataVO getUserOrderData(Long userId) {
        //获取当前线程用户id
        Long currentId = BaseContext.getCurrentId();
        if(!userId.equals(currentId)){
            log.error("用户id不匹配，订单数据获取失败");
            throw new UnauthorizedException("数据获取失败，请检查客户端登陆状态");
        }
        //根据订单状态获取订单数据
        Map map = new HashMap();
        map.put("userId",userId);
        map.put("status", OrderConstant.ORDER_STATUS_WAIT_PAY);

        //待支付订单数
        Integer waitPayOrderNum = orderMapper.getOrderNumByMap(map);

        //待出行订单数
        map.put("status", OrderConstant.ORDER_STATUS_WAIT_TRAVEL);
        Integer waitTravelOrderNum = orderMapper.getOrderNumByMap(map);

        //进行中订单数
        map.put("status", OrderConstant.ORDER_STATUS_DOING);
        Integer doingOrderNum = orderMapper.getOrderNumByMap(map);

        //已完成订单数
        map.put("status", OrderConstant.ORDER_STATUS_FINISH);
        Integer finishOrderNum = orderMapper.getOrderNumByMap(map);

        //总订单数
        map.put("status", null);
        Integer allOrderNum = orderMapper.getOrderNumByMap(map);

        return UserOrderDataVO.builder()
                .allOrderNum(allOrderNum)
                .waitPayOrderNum(waitPayOrderNum)
                .waitTravelOrderNum(waitTravelOrderNum)
                .doingOrderNum(doingOrderNum)
                .finishOrderNum(finishOrderNum)
                .build();
    }

    /**
     * 下单
     *
     * @param orderSubmitDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public OrderSubmitVO placeOrder(OrderSubmitDTO orderSubmitDTO) {
        log.info("用户下单，下单数据：{}", orderSubmitDTO);

        //对orderSubmitDTO进行参数校验
        validateOrderSubmitDTO(orderSubmitDTO);

        Long currentId = BaseContext.getCurrentId();
        // 确保用户ID匹配
        ensureUserIdMatch(currentId, orderSubmitDTO.getUserId());

        // 检查下单次数限制
        checkOrderNumLimit(orderSubmitDTO.getUserId());

        // 检查活动是否存在和活动状态
        Activity activity = ensureActivityExistAndValid(orderSubmitDTO.getActivityId());

        // 检查优惠券使用情况
        BigDecimal couponAmount = checkCouponUsage(orderSubmitDTO.getUserId(), orderSubmitDTO.getCouponId());

        // 计算实际费用
        BigDecimal amount = calculateAmount(orderSubmitDTO, couponAmount,activity);

        // 判断服务器端计算的实际应付和客户端计算的实际应付是否一致
        ensureAmountConsistency(orderSubmitDTO.getAmount(), amount);

        // 生成订单
        Orders orders = createOrder(orderSubmitDTO, amount, couponAmount, currentId,activity);

        // 插入订单详情
        insertOrderDetails(currentId,orderSubmitDTO.getOrderUserInfoList(), orders.getId());

        //构建返回数据
        return buildOrderSubmitVO(orders);
    }

    /**
     * 对orderSubmitDTO进行参数校验
     * @param orderSubmitDTO
     */
    private void validateOrderSubmitDTO(OrderSubmitDTO orderSubmitDTO) {
        // TODO: 可能对orderSubmitDTO进行详细的参数校验
        //用户id不能为空
        if (orderSubmitDTO.getUserId() == null) {
            log.error("参数错误，用户id为空");
            throw new OrderException("参数错误，用户id为空");
        }
        //活动id不能为空
        if (orderSubmitDTO.getActivityId() == null) {
            log.error("参数错误，活动id为空");
            throw new OrderException("参数错误，活动id为空");
        }
        //出行时间不能为空
        if (orderSubmitDTO.getTravelTime() == null) {
            log.error("参数错误，出行时间不能为空");
            throw new OrderException("参数错误，出行时间不能为空");
        }
        //订单人数不能为空
        if (orderSubmitDTO.getOrderUserInfoList() == null || orderSubmitDTO.getOrderUserInfoList().size() == 0) {
            log.error("参数错误，订单人数不能为空");
            throw new OrderException("参数错误，订单人数不能为空");
        }
        //判断用户信息的正确性
        for (OrderUserInfoDTO orderUserInfoDTO : orderSubmitDTO.getOrderUserInfoList()) {
            if (orderUserInfoDTO.getName() == null || orderUserInfoDTO.getName().equals("")) {
                log.error("参数错误，姓名为空");
                throw new OrderException("参数错误，姓名为空");
            }
            //TODO 使用正则初步判断用户信息正确性
            if (orderUserInfoDTO.getIdNumber() == null || orderUserInfoDTO.getIdNumber().equals(""))  {
                log.error("参数错误，用户身份证号为空");
            }
            if (orderUserInfoDTO.getPhoneNumber() == null || orderUserInfoDTO.getPhoneNumber().equals(""))  {
                log.error("参数错误，手机号为空");
                throw new OrderException("参数错误，手机号为空");
            }

        }
    }

    /**
     * 确保用户ID匹配
     */
    private void ensureUserIdMatch(Long currentId, Long userId) {
        if (userId == null || !userId.equals(currentId)) {
            log.error("用户id不匹配，订单提交失败");
            throw new OrderException("订单提交失败，请检查客户端登陆状态");
        }
    }

    /**
     * 检查下单次数限制
     * @param userId
     */
    private void checkOrderNumLimit(Long userId) {
        Map map = new HashMap<>();
        map.put("userId", userId);
        map.put("orderTime", LocalDateTime.now().minusMinutes(OrderConstant.ORDER_TIME_MINUTE_LIMIT));
        Integer orderNum = orderMapper.getOrderNumByMap(map);
        if (orderNum >= OrderConstant.ORDER_NUM_LIMIT) {
            log.error(OrderConstant.ORDER_TIME_MINUTE_LIMIT + "分钟内下单次数过多，下单失败");
            throw new OrderException("短时间内下单太多次啦，请稍后再试");
        }
    }

    /**
     * 检查活动是否存在和活动状态
     * @param activityId
     * @return
     */
    private Activity ensureActivityExistAndValid(Long activityId) {
        if (activityId == null) {
            log.error("参数错误，活动id为空");
            throw new OrderException("活动不存在");
        }
        Activity activity = activityMapper.getActivityById(activityId);
        if (activity == null) {
            log.error("活动不存在");
            throw new OrderException("活动不存在");
        }
        //判断活动是否已结束
        if (activity.getActivityEndDate().isBefore(LocalDateTime.now())) {
            log.error("活动已结束");
            throw new OrderException("活动已结束");
        }
        //判断活动是否已下架
        if (activity.getStatus() == 3) {
            log.error("活动已下架");
            throw new UnauthorizedException("活动已下架");
        }
        // 暂时注释的逻辑可以根据实际需要打开
//      //判断活动是否已开始
//      if (activity.getActivityStartDate().isAfter(LocalDateTime.now())) {
//          log.error("活动未开始");
//          throw new UnauthorizedException("活动未开始");
//      }
        //判断活动人数是否已满
//      if (activity.getParticipantLimit() <= activity.getParticipantNum()) {
//          log.error("活动人数已满");
//          throw new UnauthorizedException("活动人数已满");
//      }
        return activity;
    }

    /**
     * 检查优惠券使用情况
     * @param userId
     * @param couponId
     * @return
     */
    private BigDecimal checkCouponUsage(Long userId, Long couponId) {
        boolean isUsedFlag = false;
        if (couponId != null) {
            isUsedFlag = true;
        }
        BigDecimal couponAmount = BigDecimal.valueOf(0);
        if (isUsedFlag) {
            Coupon userCoupon = couponMapper.getCouponByUserIdAndCouponId(userId, couponId, CouponConstant.NOT_USED);
            if (couponMapper.getCouponById(couponId) == null) {
                log.error("优惠券不存在");
                throw new OrderException("优惠券不存在");
            }
            if (userCoupon == null) {
                log.error("优惠券已使用");
                throw new OrderException("下单失败，优惠券已使用");
            }
            if (userCoupon.getIsExpired() == 1) {
                log.error("优惠券已过期");
                throw new OrderException("下单失败，优惠券已过期");
            }
            couponAmount = userCoupon.getAmount();
            couponMapper.useCoupon(userId, couponId);  // 使用优惠券
        }
        return couponAmount;
    }

    /**
     * 计算实际费用
     * @param orderSubmitDTO
     * @param couponAmount
     * @return
     */
    private BigDecimal calculateAmount(OrderSubmitDTO orderSubmitDTO, BigDecimal couponAmount,Activity activity) {
        //获取活动价格
        BigDecimal activityAmount = activity.getPrice();
        //获取订单人数
        int size = orderSubmitDTO.getOrderUserInfoList().size();
        //计算订单金额
        BigDecimal amount = activityAmount.multiply(new BigDecimal(size));
        //优惠券抵扣
        return amount.subtract(couponAmount);
    }

    /**
     * 判断服务器端计算的实际应付和客户端计算的实际应付是否一致
     * @param expected 预期(客户端计算)
     * @param actual 实际(服务端计算)
     */
    private void ensureAmountConsistency(BigDecimal expected, BigDecimal actual) {
        expected = expected.setScale(2, RoundingMode.HALF_UP);
        actual = actual.setScale(2, RoundingMode.HALF_UP);
        if (!expected.equals(actual)) {
            log.error("服务器端计算的实际应付和客户端计算的实际应付不一致");
            throw new OrderException("下单失败，请检查客户端数据");
        }
    }

    /**
     * 生成订单
     * @param orderSubmitDTO
     * @param amount
     * @param couponAmount
     * @param userId
     * @param activity
     * @return
     */
    private Orders createOrder(OrderSubmitDTO orderSubmitDTO, BigDecimal amount, BigDecimal couponAmount, Long userId,Activity activity) {
        // 生成订单号
        String orderTime = String.valueOf(System.currentTimeMillis());
        String orderNumber = orderTime + userId;
        //获取当前时间
        LocalDateTime now = LocalDateTime.now();
        //获取旅游天数
        Integer travelDays = activity.getTravelDays();
        //计算该订单结束时间
        LocalDateTime endDate = orderSubmitDTO.getTravelTime().plusDays(travelDays);
        User user = userMapper.getById(userId);
        String phone = user.getPhone();
        String userName = user.getName();

        Orders orders = Orders.builder()
                .number(orderNumber)
                .userId(userId)
                .activityId(orderSubmitDTO.getActivityId())
                .couponId(orderSubmitDTO.getCouponId())
                .status(OrderConstant.ORDER_STATUS_WAIT_PAY)
                .userName(userName)
                .orderTime(now)
                .payStatus(OrderConstant.PAY_STATUS_UNPAID)
                .preferentialAmount(couponAmount)
                .amount(amount)
                .phone(phone)
                .remark(orderSubmitDTO.getRemark())
                .startDate(orderSubmitDTO.getTravelTime())
                .endDate(endDate)
                .build();

        //向订单表插入一条数据
        orderMapper.insert(orders);
        return orders;
    }

    /**
     * 插入订单详情
     * @param userId
     * @param orderUserInfoList
     * @param orderId
     */
    private void insertOrderDetails(Long userId, List<OrderUserInfoDTO> orderUserInfoList, Long orderId) {
        orderUserInfoList.forEach(orderUserInfoDTO -> {
            orderUserInfoDTO.setOrderId(orderId);
            orderUserInfoDTO.setUserId(userId);
        });
        //向订单详情表插入n条数据
        orderDetailMapper.insertBatch(orderUserInfoList);
    }

    /**
     * 构建返回数据
     * @param orders
     * @return
     */
    private OrderSubmitVO buildOrderSubmitVO(Orders orders) {
        return OrderSubmitVO.builder()
                .id(orders.getId())
                .orderNumber(orders.getNumber())
                .orderAmount(orders.getAmount())
                .orderTime(orders.getOrderTime())
                .build();
    }

    /**
     * 根据状态获取用户订单列表
     *
     * @param ordersPageQueryDTO
     * @return
     */
    @Override
    public PageResult getOrderListByStatus(OrdersPageQueryDTO ordersPageQueryDTO) {
        // 设置分页
        PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());

        Long userId = BaseContext.getCurrentId();
        Map map = new HashMap();
        map.put("userId", userId);
        map.put("status", ordersPageQueryDTO.getStatus());

        Page<Orders> page = orderMapper.getOrderListByMap(map);

        List<Orders> orderList = page.getResult();

        //获取符合条件的订单列表
//        List<Orders> orderList = orderMapper.getOrderListByMap(map);

        //返回的列表
        List<OrderVO> orderVOList = new ArrayList<>();

        //遍历订单列表
        orderList.forEach(order -> {
            //创建返回对象
            OrderVO orderVO = new OrderVO();
            //拷贝属性
            BeanUtils.copyProperties(order, orderVO);
            ImgResource image = imgResourceMapper.getActivityImageById(order.getActivityId());
            orderVO.setImage(image);
            orderVO.setActivityName(activityMapper.getActivityNameById(order.getActivityId()));
            orderVOList.add(orderVO);
        });

        return new PageResult(page.getTotal(), orderVOList);
    }

    /**
     * 评价订单
     *
     * @param commentOrderDTO
     */
    @Override
    @Transactional
    public void commentOrder(CommentOrderDTO commentOrderDTO) {
        //获取当前用户id
        Long userId = BaseContext.getCurrentId();
        Long orderId = commentOrderDTO.getOrderId();

        Map map = new HashMap();
        map.put("userId", userId);
        map.put("orderId", orderId);
        //检查该订单是否已经评价
        List<Orders> orders = orderMapper.getOrderListByMap(map);
        if (orders.size() == 0) {
            log.error(orderId + "号订单不存在，用户" + userId);
            throw new OrderException("订单不存在，评价失败");
        }
        Orders order = orders.get(0);

        if (OrderConstant.COMMENT_STATUS_YES.equals(order.getIsComment())) {
            log.error(order + "订单已评价，不能重复评价");
            throw new OrderException("该订单已评价，不能重复评价");
        }
        //订单未完成，不能评价
        if (!order.getStatus().equals(OrderConstant.ORDER_STATUS_FINISH)) {
            log.error(order + "订单未完成，不能评价");
            throw new OrderException("该订单未完成，不能评价");
        }
        //评价表插入评价
        Long activityId = order.getActivityId();
        //获取当前时间
        LocalDateTime now = LocalDateTime.now();
        Comment comment = Comment.builder()
                .activityId(activityId)
                .userId(userId)
                .commentDetail(commentOrderDTO.getContent())
                .orderId(orderId)
                .createTime(now)
                .build();
        commentMapper.commentOrder(comment);

        Orders orders1 = new Orders();
        orders1.setId(orderId);
        orders1.setIsComment(OrderConstant.COMMENT_STATUS_YES);
        orders1.setCommentId(comment.getId());

        //订单表修改状态为已评价，回填评价id
        orderMapper.updateAboutComment(orders1);
    }


    /**
     * 获取订单评价列表
     *
     * @param commentDTO
     * @return
     */
    @Override
    public List<Comment> getCommentList(CommentDTO commentDTO) {
        //如果用户id存在
        Long userId = commentDTO.getUserId();
        if (userId != null) {
            //判断用户id
            Long currentId = BaseContext.getCurrentId();

            if (!userId.equals(currentId)) {
                log.error("用户" + currentId + "无权限查看其他用户订单评价");
                throw new OrderException("请检查登陆状态");
            }
        }

        //活动id不能为空，获取活动所有评论
        if(commentDTO.getActivityId() == null){
            log.error("活动id不能为空");
            throw new OrderException("参数错误，请重试");
        }

        List<Comment> commentList = commentMapper.getCommentList(commentDTO);

        return commentList;
    }

    /**
     * 支付订单
     *
     * @param id
     */
    @Override
    public void payment(Long id) {
        //当前用户id
        Long userId = BaseContext.getCurrentId();
        //是否存在订单
        Orders orders = orderMapper.getById(id);
        if (orders == null) {
            log.error("订单不存在");
            throw new OrderException("订单不存在");
        }

        //判断订单是否属于当前用户
        if (!orders.getUserId().equals(userId)) {
            log.error("订单不属于当前用户");
            throw new OrderException("订单不属于当前用户");
        }

        //判断订单是否已支付 0未支付 1已支付 2已退款
        if (OrderConstant.PAY_STATUS_PAID.equals(orders.getPayStatus())) {
            log.error("订单已支付");
            throw new OrderException("订单已支付");
        }

        //判断订单状态 订单状态 0待付款 1待出行 2进行中 3已完成 4取消中 5已取消 6退款中 7已退款
        if (!OrderConstant.ORDER_STATUS_WAIT_PAY.equals(orders.getStatus())) {
            log.error("订单{}状态错误", orders.getId());
            throw new OrderException("订单状态错误");
        }

        //获取当前时间
        LocalDateTime now = LocalDateTime.now();

        //修改订单状态
        Orders orders1 = new Orders();
        orders1.setId(id);
        orders1.setCheckoutTime(now);
        orders1.setStatus(OrderConstant.ORDER_STATUS_WAIT_TRAVEL);
        orders1.setPayStatus(OrderConstant.PAY_STATUS_PAID);
        orderMapper.updateAboutPay(orders1);
    }

    /**
     * 取消订单
     *
     * @param userCancelOrderDTO
     */
    @Override
    public void cancel(UserCancelOrderDTO userCancelOrderDTO) {
        //判断订单是否存在
        Orders orders = orderMapper.getById(userCancelOrderDTO.getId());

        //判断订单是否存在
        if (orders == null) {
            log.error("订单不存在");
            throw new OrderException("订单不存在");
        }

        //获取当前用户id
        Long userId = BaseContext.getCurrentId();

        //判断订单是否属于当前用户
        if (!orders.getUserId().equals(userId)) {
            log.error("订单不属于当前用户");
            throw new OrderException("订单不属于当前用户");
        }

        //订单状态 0待付款 1待出行 2进行中 3已完成 4取消中 5已取消 6退款中 7已退款

        Orders orders1 = new Orders();
        orders1.setId(orders.getId());
        //判断订单是否已支付
        if (OrderConstant.PAY_STATUS_PAID.equals(orders.getPayStatus())) {
            log.error("已支付订单{}，取消订单", orders.getId());
            //退款
            //refundService.refund(orders.getId());

            //修改订单支付状态
            orders1.setPayStatus(OrderConstant.PAY_STATUS_REFUND);
        }

        if (orders.getStatus() < 2) {
            //修改订单状态
            orders1.setStatus(OrderConstant.ORDER_STATUS_CANCEL);
        } else {
            log.error("订单{}状态为{}，不能取消", orders.getId(), orders.getStatus());
            throw new OrderException("订单状态错误，不能取消");
        }

        //获取当前时间
        LocalDateTime now = LocalDateTime.now();
        orders1.setCancelTime(now);

        //设置取消原因
        orders1.setCancelReason(userCancelOrderDTO.getCancelReason());

        orderMapper.updateAboutCancel(orders1);
    }

    /**
     * 根据id获取订单
     *
     * @param id
     * @return
     */
    @Override
    public OrdersDetailVO getOrderById(Long id) {

        if (id == null) {
            log.error("订单id不能为空");
            throw new OrderException("订单id不能为空");
        }
        //判断订单是否存在
        Orders orders = orderMapper.getById(id);
        if (orders == null) {
            log.error("订单不存在");
            throw new OrderException("订单不存在");
        }
        //判断订单是否属于当前用户
        if (!orders.getUserId().equals(BaseContext.getCurrentId())) {
            log.error("订单不属于当前用户");
            throw new OrderException("订单不属于当前用户");
        }

        OrdersDetailVO ordersDetailVO = new OrdersDetailVO();
        BeanUtils.copyProperties(orders, ordersDetailVO);

        //获取订单用户信息
        List<OrderUserInfoDTO> orderUserInfoList = orderDetailMapper.getByOrderId(id);

        //设置订单用户信息
        ordersDetailVO.setOrderUserInfoList(orderUserInfoList);
        //返回订单
        return ordersDetailVO;
    }
}
